#include "libPPD.h"

int32_t planificarPedidoPRAID (t_NIPC paquete)
{
	extern tCabezal cabezal;
	extern t_listaPRAID *listaPedidosPRAID;
	extern pthread_mutex_t bloqueaLista;
	t_CHS sectorCHS;

	loguearTipoPedido(paquete);

	if (listaPedidosPRAID->head == NULL)
	{
		pthread_mutex_lock(&bloqueaLista);
		agregarEnLaListaPRAID (0, paquete);
		pthread_mutex_unlock(&bloqueaLista);
	}
	else
	{
		pasarACHS (paquete.nroSector, &sectorCHS);

		if (cabezal.posActual.C <= sectorCHS.C)
		{
			//el nuevo pedido esta a la pasada del cabezal en orden ascendente.
			insertarDespuesDeCabezalPRAID(paquete);

		}
		else
		{
			//el nuevo pedido esta "atras" del cabezal, por lo que éste lo atenderá cuando vuelva a empezar.
			insertarAntesDeCabezalPRAID(paquete);
		}
	}
	return Retorno_OK;
}


int32_t planificarPedidoPFS (t_NIPC paquete, int32_t socketFD)
{
	extern tCabezal cabezal;
	extern t_listaPFS *listaPedidosPFS;
	extern pthread_mutex_t bloqueaLista;

	t_CHS sectorCHS;

	loguearTipoPedido(paquete);

	if (listaPedidosPFS->head == NULL)
	{
		pthread_mutex_lock(&bloqueaLista);
		agregarEnLaListaPFS (0, paquete, socketFD);
		pthread_mutex_unlock(&bloqueaLista);
	}
	else
	{
		pasarACHS (paquete.nroSector, &sectorCHS);

		if (cabezal.posActual.C <= sectorCHS.C)
		{
			//el nuevo pedido esta a la pasada del cabezal en orden ascendente.
			insertarDespuesDeCabezalPFS(paquete, socketFD);

		}
		else
		{
			//el nuevo pedido esta "atras" del cabezal, por lo que éste lo atenderá cuando vuelva a empezar.
			insertarAntesDeCabezalPFS(paquete, socketFD);
		}
	}

	return Retorno_OK;
}



void insertarDespuesDeCabezalPRAID (t_NIPC paqueteNuevo)
{
	extern t_listaPRAID *listaPedidosPRAID;
	extern pthread_mutex_t bloqueaLista;
	extern tCabezal cabezal;
	int32_t bloquearLista = 0;

	int32_t posicion = 0;
	int32_t salir = 0;
	int32_t bloquearCabezal = 0;
	int32_t pistaNodo, pistaNuevoNodo;

	bloquearLista = pthread_mutex_lock(&bloqueaLista);

	t_nodoPRAID * nodo;
	nodo = listaPedidosPRAID->head;
	if (listaPedidosPRAID->head == NULL)
		agregarEnLaListaPRAID (0, paqueteNuevo);
	else
	{
		pistaNodo = numeroPista(nodo->paquete.nroSector);
		pistaNuevoNodo = numeroPista(paqueteNuevo.nroSector);

		/* mientra que la pista del que esta en la lista sea mayor o igual al cabezal, porque si es menor deberia atenderlo a la vuelta,
		sea menor al nuevo que quiero insertar para que quede ordenado ascendente,
		y salir distinto de uno para que se sepa si es el ultimo nodo de la lista y no se puede avanzar más */
		bloquearCabezal = pthread_mutex_lock(&cabezal.bloqueaCabezal);
		while ((pistaNodo >= cabezal.posActual.C) && (pistaNodo < pistaNuevoNodo ) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}

		}
		bloquearCabezal = pthread_mutex_unlock(&cabezal.bloqueaCabezal);

		salir = 0;
		while ((pistaNodo == pistaNuevoNodo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
				//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posición más.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
						salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else //las pistas son iguales pero no son el mismo sector, hago fifo, primero la que ya estaba.
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}

			}
		}
		agregarEnLaListaPRAID (posicion, paqueteNuevo);
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaLista);
}



void insertarAntesDeCabezalPRAID (t_NIPC paqueteNuevo)
{
	extern tCabezal cabezal;
	extern t_listaPRAID *listaPedidosPRAID;
	extern pthread_mutex_t bloqueaLista;
	int32_t bloquearLista = 0;
	int32_t bloquearCabezal = 0;

	t_CHS sectorAux;
	int32_t salir = 0;
	int32_t posicion = 0;

	bloquearLista = pthread_mutex_lock(&bloqueaLista);

	t_nodoPRAID * nodo;
	nodo = listaPedidosPRAID->head;
	if (listaPedidosPRAID->head == NULL)
		agregarEnLaListaPRAID (0, paqueteNuevo);
	else
	{
		pasarACHS (nodo->paquete.nroSector, &sectorAux);

		// quiero saltear a todos los que van primero, o sea, los que tienen pista mayor o igual a la del cabezal
		bloquearCabezal = pthread_mutex_lock(&cabezal.bloqueaCabezal);
		while ((cabezal.posActual.C <= sectorAux.C) && (salir == 0))
		{
			posicion++;
			if (nodo->next == NULL) //No hay más, así que lo agrego último.
			{
				agregarEnLaListaPRAID(posicion, paqueteNuevo);
				salir = 1;
			}
			else
			{
				nodo = nodo->next;
				pasarACHS (nodo->paquete.nroSector, &sectorAux);
			}
		}
		bloquearCabezal = pthread_mutex_unlock(&cabezal.bloqueaCabezal);

		int32_t pistaNodo, pistaNuevoNodo;

		pistaNodo = numeroPista(nodo->paquete.nroSector);
		pistaNuevoNodo = numeroPista(paqueteNuevo.nroSector);

		//si el nodo nuevo que quiero agregar es mas chico que el de la lista, inserto el nuevo antes.
		if (salir != 1)
		{
			if(pistaNodo > pistaNuevoNodo)
			agregarEnLaListaPRAID (posicion, paqueteNuevo);
			else
			{
				while ((pistaNodo < pistaNuevoNodo ) && (salir != 1)) //mientras que el nuevo sea más grande y la lista no termine
				{
					posicion++;
					if (nodo->next == NULL)
						salir = 1;
					else
					{
						nodo = nodo->next;
						pistaNodo = numeroPista(nodo->paquete.nroSector);
					}
				}
				salir = 0;
				//mismo que caso anterior, caso en que las pistas son iguales.
				while ((pistaNodo == pistaNuevoNodo) && (salir != 1))
				{
					if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
					{
						while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
						{
							//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posición más.
							if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
							{
								posicion++;
								if (nodo->next == NULL)
									salir = 1;
								else
								{
									nodo = nodo->next;
									pistaNodo = numeroPista(nodo->paquete.nroSector);
								}
							}
							else
								salir = 1;
						}
					}
					else //pistas iguales, sectores distintos. Van por FIFO
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}

					}
				}
			}
			agregarEnLaListaPRAID (posicion, paqueteNuevo);
		}
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaLista);
}



void insertarDespuesDeCabezalPFS (t_NIPC paqueteNuevo, int32_t socketFD)
{
	extern t_listaPFS *listaPedidosPFS;
	extern pthread_mutex_t bloqueaLista;
	extern tCabezal cabezal;
	int32_t bloquearLista = 0;

	int32_t posicion = 0;
	int32_t salir = 0;
	int32_t bloquearCabezal = 0;
	int32_t pistaNodo, pistaNuevoNodo;

	bloquearLista = pthread_mutex_lock(&bloqueaLista);

	t_nodoPFS * nodo;
	nodo = listaPedidosPFS->head;
	if (listaPedidosPFS->head == NULL)
		agregarEnLaListaPFS(0, paqueteNuevo, socketFD);
	else
	{
		pistaNodo = numeroPista(nodo->paquete.nroSector);
		pistaNuevoNodo = numeroPista(paqueteNuevo.nroSector);

		bloquearCabezal = pthread_mutex_lock(&cabezal.bloqueaCabezal);
		while ((pistaNodo >= cabezal.posActual.C) && (pistaNodo < pistaNuevoNodo ) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}

		}
		bloquearCabezal = pthread_mutex_unlock(&cabezal.bloqueaCabezal);

		salir = 0;
		while ((pistaNodo == pistaNuevoNodo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
					//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posición más.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}
			}
		}
		agregarEnLaListaPFS (posicion, paqueteNuevo, socketFD);
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaLista);
}


void insertarAntesDeCabezalPFS (t_NIPC paqueteNuevo, int32_t socketFD)
{
	extern tCabezal cabezal;
	extern t_listaPFS *listaPedidosPFS;
	extern pthread_mutex_t bloqueaLista;
	int32_t bloquearLista = 0;
	int32_t bloquearCabezal = 0;

	t_NIPC paqueteAux;
	t_CHS sectorAux;
	int32_t salir = 0;
	int32_t posicion = 0;

	bloquearLista = pthread_mutex_lock(&bloqueaLista);

	t_nodoPFS * nodo;
	nodo = listaPedidosPFS->head;
	if (listaPedidosPFS->head == NULL)
		agregarEnLaListaPFS(0, paqueteNuevo, socketFD);
	else
	{
		paqueteAux = nodo->paquete;
		pasarACHS (paqueteAux.nroSector, &sectorAux);

		bloquearCabezal = pthread_mutex_lock(&cabezal.bloqueaCabezal);
		while ((cabezal.posActual.C <= sectorAux.C) && (salir == 0))
		{
			posicion++;
			if (nodo->next == NULL)
			{
				agregarEnLaListaPFS (posicion, paqueteNuevo, socketFD);
				salir = 1;
			}
			else
			{
				nodo = nodo->next;
				paqueteAux = nodo->paquete;
				pasarACHS (paqueteAux.nroSector, &sectorAux);
			}
		}
		bloquearCabezal = pthread_mutex_unlock(&(cabezal.bloqueaCabezal));

		int32_t pistaNodo, pistaNuevoNodo;
		t_NIPC  paquete;

		paquete = nodo->paquete;
		pistaNodo = numeroPista(paquete.nroSector);
		pistaNuevoNodo = numeroPista(paqueteNuevo.nroSector);
		if (salir != 1)
		{
			if(pistaNodo > pistaNuevoNodo)
				agregarEnLaListaPFS (posicion, paqueteNuevo, socketFD);
			else
			{
				while ((pistaNodo < pistaNuevoNodo ) && (salir != 1))
				{
					posicion++;
					if (nodo->next == NULL)
						salir = 1;
					else
					{
						nodo = nodo->next;
						paquete = nodo->paquete;
						pistaNodo = numeroPista(paquete.nroSector);
					}
				}
				salir = 0;
				while ((pistaNodo == pistaNuevoNodo) && (salir != 1))
				{
					if (paquete.nroSector == paqueteNuevo.nroSector)
					{
						while ((paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
						{
							//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posición más.
							if (paquete.PayloadDescriptor == ESCRIBIRSECTOR)
							{
								posicion++;
								if (nodo->next == NULL)
									salir = 1;
								else
								{
									nodo = nodo->next;
									paquete = nodo->paquete;
									pistaNodo = numeroPista(paquete.nroSector);
								}
							}
							else
								salir = 1;
						}
					}
					else
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							paquete = nodo->paquete;
							pistaNodo = numeroPista(paquete.nroSector);
						}

					}
				}
			}
			agregarEnLaListaPFS (posicion, paqueteNuevo, socketFD);
		}
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaLista);
}


